﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Reflection;
using System.Reactive.Concurrency;
using System.Windows.Markup;

using agree.schema;

using alib;
using alib.Collections;
using alib.Enumerable;
using alib.Debugging;

namespace agree.configuration
{
	using SysType = System.Type;

	public interface IConfigSection : IIdentity
	{
		IConfigSection ConfigParent { get; }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class AgreeConfig : _monad<AgreeConfig>, IConfigSection
	{
		public AgreeConfig(IRtParent parent, AgreeConfig loader)
			: base(parent, loader)
		{
			c_required_args = 0;
		}

		public AgreeConfig(IRtParent parent)
			: this(parent, default(AgreeConfig))
		{
		}

		IConfigSection IConfigSection.ConfigParent { get { return null; } }

		public override Object ProvideValue(IServiceProvider sp)
		{
			base.ProvideValue(sp);

			return this.Loader;
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public AgreeConfig Loader
		{
			get { return t0 ?? this; }
			set
			{
				if (t0 != null)
					throw new Exception();

				this._types = value._types;
				this._grammar = value._grammar;
				this._lexicon = value._lexicon;
				this._nodelabels = value._nodelabels;
				this._morphology = value._morphology;
				this._lexdependencies = value._lexdependencies;
				this._tokenmapping = value._tokenmapping;
				this._parser = value._parser;
				this._mrs = value._mrs;
				this._generator = value._generator;
				this._triggerrules = value._triggerrules;
			}
		}

		TypesConfig _types;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TypesConfig Types
		{
			get { return _types ?? (_types = new TypesConfig(this)); }
		}

		GrammarConfig _grammar;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public GrammarConfig Grammar
		{
			get { return _grammar ?? (_grammar = new GrammarConfig(this)); }
		}

		LexiconConfig _lexicon;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public LexiconConfig Lexicon
		{
			get { return _lexicon ?? (_lexicon = new LexiconConfig(this)); }
		}

		NodeLabelsConfig _nodelabels;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public NodeLabelsConfig NodeLabels
		{
			get { return _nodelabels ?? (_nodelabels = new NodeLabelsConfig(this)); }
		}

		MorphologyConfig _morphology;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public MorphologyConfig Morphology
		{
			get { return _morphology ?? (_morphology = new MorphologyConfig(this)); }
		}

		LexDependenciesConfig _lexdependencies;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public LexDependenciesConfig LexDependencies
		{
			get { return _lexdependencies ?? (_lexdependencies = new LexDependenciesConfig(this)); }
		}

		TokenMappingConfig _tokenmapping;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TokenMappingConfig TokenMapping
		{
			get { return _tokenmapping ?? (_tokenmapping = new TokenMappingConfig(this)); }
		}

		MrsConfig _mrs;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public MrsConfig Mrs
		{
			get { return _mrs ?? (_mrs = new MrsConfig(this)); }
		}

		ParserConfig _parser;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public ParserConfig Parser
		{
			get { return _parser ?? (_parser = new ParserConfig(this)); }
		}

		GeneratorConfig _generator;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public GeneratorConfig Generator
		{
			get { return _generator ?? (_generator = new GeneratorConfig(this)); }
		}

		TriggerRulesConfig _triggerrules;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TriggerRulesConfig TriggerRules
		{
			get { return _triggerrules ?? (_triggerrules = new TriggerRulesConfig(this)); }
		}

		//public RulePreCheckConfig RulePreCheck { get;private set ?? (_types = new TypesConfig(this)); }

		//public override IEnumerable<ValidationResult> Validate(ValidationContext ctx)
		//{
		//	var sp = Generator.Chart.PackingRestrictors;
		//	if (sp == null)
		//		Generator.Chart.Packing = ChartConfig.PackingOpts.None;

		//	sp = Parser.Chart.PackingRestrictors;
		//	if (sp == null)
		//		Parser.Chart.Packing = ChartConfig.PackingOpts.None;

		//	yield break;
		//}
	};

	[UsableDuringInitialization(true)]
	public abstract class ConfigSection : identity_base, IConfigSection
	{
		public ConfigSection(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this.parent_sect = parent_sect;
		}

		readonly IConfigSection parent_sect;
		public IConfigSection ConfigParent { get { return parent_sect; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public AgreeConfig Root
		{
			get
			{
				AgreeConfig ac;
				IConfigSection ps = this;
				do
					if ((ac = ps as AgreeConfig) != null)
						return ac;
				while ((ps = ps.ConfigParent) != null);
				throw new Exception();
			}
		}
	};

	public abstract class ConfigSection<S> : ConfigSection
	{
		public ConfigSection(IConfigSection parent_sect)
			: base(parent_sect)
		{
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class JobConfig : ConfigSection<JobConfig>
	{
		public JobConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this.TasksMax = int.MaxValue;
			this.timeout_sec = Double.MaxValue;
			this.Verbose = 0;
			this.RecordPerformanceStatistics = true;
			this.ThreadSafeStatistics = true;
			this.MemLimit = long.MaxValue;
		}

		public bool RecordPerformanceStatistics { get; set; }

		public bool ThreadSafeStatistics { get; set; }

		public int TasksMax { get; set; }

		public long MemLimit { get; set; }

		public int Verbose { get; set; }

		/// <summary>
		/// Number of seconds allowed per parse. If the parse is not complete within this amount of time,
		/// the parse will be aborted with a ParseTimeoutException.
		/// </summary>
		Double timeout_sec;
		public Double JobTimeoutSeconds
		{
			get { return timeout_sec; }
			set { timeout_sec = value; }
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class TypesConfig : ConfigSection<TypesConfig>
	{
		public TypesConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this.TopType = "*top*";
			this.StringType = "string";

			this.TypesList = "*list*";
			this.TypesEmptyList = "*null*";
			this.TypesDiffList = "diff-list";

			this.ListHead = "FIRST";
			this.ListTail = "REST";
			this.DlistList = "LIST";
			this.DlistLast = "LAST";

			this.GlbCacheBucketCount = 80747;
			this.GlbCacheOptions = GlbCacheOptionsEnum.PreCacheAuthoredTypes |
									GlbCacheOptionsEnum.PreCacheSpawnTask;
		}

		public const int TopId = 0;

		public String TopType { get; set; }
		public String StringType { get; set; }

		public String TypesList { get; set; }
		public String TypesEmptyList { get; set; }
		public String TypesDiffList { get; set; }

		public String ListHead { get; set; }
		public String ListTail { get; set; }
		public String DlistList { get; set; }
		public String DlistLast { get; set; }

		public GlbCacheOptionsEnum GlbCacheOptions { get; set; }
		public uint GlbCacheBucketCount { get; set; }

		[Flags]
		public enum GlbCacheOptionsEnum
		{
			Disable = 0,
			PreCacheAuthoredTypes = /*		*/ 0x00000001,
			PreCacheBcpoTypes = /*			*/ 0x00000002,
			PreCacheSpawnTask = /*			*/ 0x00000004,
			PreCacheTaskLowerPriority = /*	*/ 0x00000008,
		};
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class LexiconConfig : ConfigSection<LexiconConfig>
	{
		public LexiconConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this.RelIndexCache = GenIndexCacheMode.ReadWrite;
			this.LexicalComparison = StringComparer.InvariantCultureIgnoreCase;
		}

		public IEqualityComparer<String> LexicalComparison { get; set; }

		[Flags]
		public enum GenIndexCacheMode
		{
			None = 0,
			Read = 1,
			Write = 2,
			ReadWrite = 3,
			Rebuild = Write,
		};

		public GenIndexCacheMode RelIndexCache { get; set; }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class GrammarConfig : ConfigSection<GrammarConfig>
	{
		public GrammarConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this.KeyDaughterValue = "+";
		}

		public String KeyDaughterValue { get; set; }

		HashSet<String> delete_dtrs;
		public HashSet<String> DeletedDaughters
		{
			get { return delete_dtrs ?? (delete_dtrs = new HashSet<String>(StringComparer.InvariantCultureIgnoreCase)); }
			set { delete_dtrs = value; }
		}

		HashSet<String> span_only;
		public HashSet<String> SpanOnlyRules
		{
			get { return span_only ?? (span_only = new HashSet<String>(StringComparer.InvariantCultureIgnoreCase)); }
			set { span_only = value; }
		}

		BootstrapFsPath orth_path;
		public BootstrapFsPath OrthPath
		{
			get
			{
				if (orth_path == null)
					orth_path = new BootstrapFsPath(this, "STEM");
				return orth_path;
			}
			set
			{
				if (value == null || value == orth_path)
					return;
				orth_path = value;
			}
		}

		BootstrapFsPath ruleargs_path;
		public BootstrapFsPath RuleArgsPath
		{
			get
			{
				if (ruleargs_path == null)
					ruleargs_path = new BootstrapFsPath(this, "ARGS");
				return ruleargs_path;
			}
			set
			{
				if (value == null || value == ruleargs_path)
					return;
				ruleargs_path = value;
			}
		}

		BootstrapFsPath keydtr_path;
		public BootstrapFsPath KeyDaughterPath
		{
			get
			{
				if (keydtr_path == null)
					keydtr_path = new BootstrapFsPath(this, "KEY-ARG");
				return keydtr_path;
			}
			set
			{
				if (value == null || value == keydtr_path)
					return;
				keydtr_path = value;
			}
		}

		BootstrapFsPath headdtr_path;
		public BootstrapFsPath HeadDaughterPath
		{
			get
			{
				if (headdtr_path == null)
					return BootstrapFsPath.Empty;
				return headdtr_path;
			}
			set
			{
				if (value == null || value == headdtr_path)
					return;
				headdtr_path = value;
			}
		}

		BootstrapFsPath rname_path;
		public BootstrapFsPath RuleMonikerPath
		{
			get
			{
				if (rname_path == null)
					return BootstrapFsPath.Empty;
				return rname_path;
			}
			set
			{
				if (value == null || value == rname_path)
					return;
				rname_path = value;
			}
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class MrsConfig : ConfigSection<MrsConfig>
	{
		public MrsConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this.LexKeyrelPath = new BootstrapFsPath(this, "SYNSEM.LKEYS.KEYREL");
			this.LexAltKeyrelPath = new BootstrapFsPath(this, "SYNSEM.LKEYS.ALTKEYREL");

			this.CContPath = new BootstrapFsPath(this, "C-CONT");

			this.XargPath = new BootstrapFsPath(this, "HOOK.XARG");

			this.RelationSuffix = "_rel";

			this.HookFeat = "HOOK";
			this.IndexFeat = "INDEX";
			this.LblFeat = "LBL";
			this.PredFeat = "PRED";
			this.BodyFeat = "BODY";
			this.RstrFeat = "RSTR";
			this.Arg0Feat = "ARG0";
			this.CargFeat = "CARG";
			this.SkolemFeat = "INSTLOC";

			this.EventType = "event";
			this.RefIndType = "ref-ind";
			this.NonExplIndType = "non_expl-ind";
			this.DegIndType = "deg-ind";
			this.HandleType = "handle";
			this.NonEventType = "non_event";
			this.EventOrIndexType = "event_or_index";
		}

		public String RelationSuffix { get; set; }

		public BootstrapFsPath LexKeyrelPath { get; set; }
		public BootstrapFsPath LexAltKeyrelPath { get; set; }

		public BootstrapFsPath InitialSemanticsPath { get; set; }
		public BootstrapFsPath CContPath { get; set; }
		public BootstrapFsPath RelsPath { get; set; }
		public BootstrapFsPath HconsPath { get; set; }
		public BootstrapFsPath IconsPath { get; set; }
		public BootstrapFsPath RelPredPath { get; set; }
		public BootstrapFsPath RelLblPath { get; set; }
		public BootstrapFsPath LtopPath { get; set; }	// don't initialize this, some grammars might want 'floating LTOP'
		public BootstrapFsPath IndexPath { get; set; }
		public BootstrapFsPath XargPath { get; set; }

		public String HookFeat { get; set; }
		public String IndexFeat { get; set; }
		public String LblFeat { get; set; }
		public String PredFeat { get; set; }
		public String Arg0Feat { get; set; }
		public String BodyFeat { get; set; }
		public String RstrFeat { get; set; }
		public String HargFeat { get; set; }
		public String LargFeat { get; set; }
		public String CargFeat { get; set; }
		public String SkolemFeat { get; set; }

		public String[] ValueFeats { get; set; }
		public String[] IgnoredSemFeatures { get; set; }
		public String[] IgnoredExtraFeatures { get; set; }

		public String CFrom { get; set; }
		public String CTo { get; set; }

		public String EventType { get; set; }
		public String IndividualType { get; set; }
		public String FullRefIndType { get; set; }
		public String RefIndType { get; set; }
		public String NonExplIndType { get; set; }
		public String DegIndType { get; set; }
		public String ConjIndType { get; set; }
		public String HandleType { get; set; }
		public String NonEventType { get; set; }
		public String EventOrIndexType { get; set; }

		public String[] FeatPriorityList { get; set; }
		public String[] ExtraPriorityList { get; set; }
	};



	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class TriggerRulesConfig : ConfigSection<TriggerRulesConfig>
	{
		public TriggerRulesConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			ContextFeat = "CONTEXT";
			InputFeat = "INPUT";
			OutputFeat = "OUTPUT";
			FilterFeat = "FILTER";

			TriggerPath = new BootstrapFsPath(this, "flags.trigger");
		}

		public BootstrapFsPath TriggerPath { get; set; }
		public String ContextFeat { get; set; }
		public String InputFeat { get; set; }
		public String OutputFeat { get; set; }
		public String FilterFeat { get; set; }
	};

#if false
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class RulePreCheckConfig : ConfigSection<RulePreCheckConfig>
	{
		public RulePreCheckConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this._ena = true;
		}

		bool _ena;
		public bool Enable
		{
			get { return _ena; }
			set { _ena = value; }
		}
	};
#endif

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class RewriterConfig
	{
		public RewriterConfig()
		{
			this.RuleApplicationLimit = 80;
			this.RuleApplicationLimitTotal = 500;
			this.EdgeLimit = 1000;
		}

		public int RuleApplicationLimit { get; set; }

		public int RuleApplicationLimitTotal { get; set; }

		public int EdgeLimit { get; set; }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class TokenMappingConfig : ConfigSection<TokenMappingConfig>
	{
		public TokenMappingConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			_rwcfg = new configuration.RewriterConfig();
			TokenCargPath = new BootstrapFsPath(this, "+CARG");
		}

		RewriterConfig _rwcfg;
		public RewriterConfig RewriterConfig { get { return _rwcfg; } }

		public BootstrapFsPath LexiconTokensPath { get; set; }
		public BootstrapFsPath LexiconLastTokenPath { get; set; }
		public BootstrapFsPath TokenFormPath { get; set; }
		public BootstrapFsPath TokenCargPath { get; set; }
		public BootstrapFsPath TokenIdPath { get; set; }
		public BootstrapFsPath TokenFromPath { get; set; }
		public BootstrapFsPath TokenToPath { get; set; }
		public BootstrapFsPath TokenPostagsPath { get; set; }
		public BootstrapFsPath TokenPosprobsPath { get; set; }

		public BootstrapFsPath ChartMappingContextPath { get; set; }
		public BootstrapFsPath ChartMappingInputPath { get; set; }
		public BootstrapFsPath ChartMappingOutputPath { get; set; }
		public BootstrapFsPath ChartMappingPositionPath { get; set; }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class UnificationConfig : ConfigSection<UnificationConfig>
	{
		public UnificationConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this._qc = new HashSet<String>(StringComparer.InvariantCultureIgnoreCase);
		}

		HashSet<String> _qc;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public HashSet<String> QuickCheckPaths
		{
			get { return _qc; }
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class MorphologyConfig : ConfigSection<MorphologyConfig>
	{
		public MorphologyConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this._job = new JobConfig(this);
			this._ucfg = new UnificationConfig(this);

			this.IsIrregularFormsOnly = false;
			this.IsLexEntriesCanFail = false;
			this.AllowEmptyRegularForms = false;
			this.MaximumLexRuleApplications = int.MaxValue;
		}

		readonly JobConfig _job;
		public JobConfig Job { get { return _job; } }

		readonly UnificationConfig _ucfg;
		public UnificationConfig Unification { get { return _ucfg; } }

		public bool IsIrregularFormsOnly { get; set; }

		public bool IsLexEntriesCanFail { get; set; }

		public int MaximumLexRuleApplications { get; set; }

		/// <summary>
		/// Using LKB-style Regex morphology, it may be possible to hypothesize empty orthographic forms. The default
		/// for this setting is 'false,' which prevents hypothesizing such transformations.
		/// </summary>
		public bool AllowEmptyRegularForms { get; set; }

		/// <summary>
		/// If 'true', the presence of an irregular form in a morphological analysis hypothesis will
		/// block the proposal of any regularly inflected forms.
		/// </summary>
		public bool IrregularFormsOnly
		{
			get { return IsIrregularFormsOnly; }
			set { IsIrregularFormsOnly = value; }
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class LexDependenciesConfig : ConfigSection<LexDependenciesConfig>
	{
		public LexDependenciesConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this.chart_dependency_scope = DependencyScope.TwoWay;
		}

		public enum DependencyScope
		{
			Unidirectional,
			TwoWay,
		};

		DependencyScope chart_dependency_scope;
		public DependencyScope ChartDependencyScope
		{
			get { return chart_dependency_scope; }
			set { chart_dependency_scope = value; }
		}

		Pairing<String>[] chart_dependency_path_tmp;
		public Pairing<String>[] BootstrapChartDependencyPaths
		{
			set
			{
				chart_dependency_path_tmp = value == null ?
					  alib.Collections.Collection<Pairing<String>>.None :
					  value.Select(kvp => new Pairing<String>(kvp.x, kvp.y)).ToArray();
			}
			get { return chart_dependency_path_tmp; }
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class ChartConfig : ConfigSection<ChartConfig>
	{
		public ChartConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			_job = new JobConfig(this);
			_ucfg = new UnificationConfig(this);

			_key_strategy = KeyStrategy.KeyDriven;
			_pack_opts = PackingOpts.Full;
			_col_limit = 80;
			_token_limit = 300;
			_deriv_limit = int.MaxValue;
			_edge_limit = 50000;
		}

		readonly JobConfig _job;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public JobConfig Job
		{
			get { return _job; }
		}

		readonly UnificationConfig _ucfg;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public UnificationConfig Unification
		{
			get { return _ucfg; }
		}

		IgnoreRules _ignore_rules;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public IgnoreRules IgnoreRules
		{
			get
			{
				if (_ignore_rules != null)
					return _ignore_rules;
				return _ignore_rules = new IgnoreRules(this);
			}
			set { _ignore_rules = value; }
		}

		HashSet<String> _rstr;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public HashSet<String> PackingRestrictors
		{
			get
			{
				if (_rstr != null)
					return _rstr;
				return _rstr = new HashSet<String>(Collection<String>.NoneColl, StringComparer.InvariantCultureIgnoreCase);
			}
			set { _rstr = value; }
		}

		HashSet<String> _rgss;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public HashSet<String> StartSymbols
		{
			get
			{
				if (_rgss != null)
					return _rgss;
				return _rgss = new HashSet<String>(Collection<String>.NoneColl, StringComparer.InvariantCultureIgnoreCase);
			}
			set { _rgss = value; }
		}

		String _nir;
		public String NonIdiomRoot
		{
			get { return _nir; }
			set { _nir = value; }
		}

		[Flags]
		public enum PackingOpts : sbyte
		{
			None = 0,
			Proactive = 1,
			Retroactive = 2,
			Equivalence = 3,
			Full = Equivalence,

			Only = 4,
			ProactiveOnly = Proactive | Only,
			RetroactiveOnly = Retroactive | Only,
			EquivalenceOnly = Equivalence | Only,
			Any = Proactive | Retroactive,
		};

		protected PackingOpts _pack_opts;
		public PackingOpts Packing
		{
			get { return _pack_opts; }
			set { _pack_opts = value; }
		}

		/// <summary>
		/// Options for configuring which rule daughter the parser will try to unify first
		/// </summary>
		public enum KeyStrategy
		{
			/// <summary>
			/// The parser will unify the rule daughter whose key feature (configurable) has a certain key
			/// value (configurable)
			/// </summary>
			KeyDriven,	// use, e.g.  KEY-ARG +
			/// <summary>
			/// The parser will unify rule daughters left-to-right
			/// </summary>
			LeftToRight,
			/// <summary>
			/// The parser will unify rule daughters right-to-left
			/// </summary>
			RightToLeft,
			/// <summary>
			/// The parser will unify the rule daughter that is designated as the head daughter
			/// </summary>
			HeadDaughter,	// use, e.g. HD-DTR		(todo)
		};

		/// <summary>
		/// Strategy used by the parser to determine which of a mother rule's unifications to perform
		/// first. The available options are documented in ParseConfiguration.KeyStrategy
		/// </summary>
		public KeyStrategy Strategy
		{
			get { return _key_strategy; }
			set { _key_strategy = value; }
		}
		protected KeyStrategy _key_strategy;

		/// <summary>
		/// max number of columns
		/// </summary>
		public int ColumnLimit
		{
			get { return _col_limit; }
			set { _col_limit = value; }
		}
		protected int _col_limit;

		public int DerivationLimit
		{
			get { return _deriv_limit; }
			set { _deriv_limit = value; }
		}
		protected int _deriv_limit;

		/// <summary>
		/// max number of initial items
		/// </summary>
		public int TokenLimit
		{
			get { return _token_limit; }
			set { _token_limit = value; }
		}
		protected int _token_limit;

		/// <summary>
		/// max number of edges
		/// </summary>
		public int MaxEdges
		{
			get { return _edge_limit; }
			set { _edge_limit = value; }
		}
		protected int _edge_limit;

#if true
		public void _dump_effective_settings()
		{
			Debug.Print("Unification: {0}", Unification == null ? "(null)" : Unification.ToString());
			Debug.Print("Job: {0}", Job == null ? "(null)" : Job.ToString());
			Debug.Print("NonIdiomRoot: {0}", NonIdiomRoot == null ? "(null)" : NonIdiomRoot.ToString());
			Debug.Print("IgnoreRules: {0}", IgnoreRules == null ? "(null)" : IgnoreRules.StringJoin(","));
			Debug.Print("StartSymbols: {0}", StartSymbols == null ? "(null)" : StartSymbols.StringJoin(","));
			Debug.Print("PackingRestrictors: {0}", PackingRestrictors == null ? "(null)" : PackingRestrictors.StringJoin(","));

			Debug.Print("Strategy: {0}", Strategy);
			Debug.Print("Packing: {0}", Packing);
			Debug.Print("ColumnLimit: {0}", ColumnLimit);
			Debug.Print("DerivationLimit: {0}", DerivationLimit);
			Debug.Print("MaxEdges: {0}", MaxEdges);
			Debug.Print("TokenLimit: {0}", TokenLimit);
		}
#endif
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class chart_controller<T> : ConfigSection<T>
	{
		public chart_controller(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this._cc = new ChartConfig(this);
		}

		protected readonly ChartConfig _cc;
		public ChartConfig Chart { get { return _cc; } }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class ParserConfig : chart_controller<ParserConfig>
	{
		public ParserConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
		}

		public HashSet<Char> PunctuationChars { get; set; }

		public bool IsAutotune { get; set; }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class GeneratorConfig : chart_controller<GeneratorConfig>,
		ρρDuplicateLexIds
	{
		public GeneratorConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this._dli = new DuplicateLexIds(Root);

			_cc.StartSymbols.Add("root_strict");
			_cc.StartSymbols.Add("utterance-root");
		}

		DuplicateLexIds _dli;
		public DuplicateLexIds DuplicateLexIds
		{
			get { return _dli; }
			set { _dli = value; }
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public sealed class NodeLabelsConfig : ConfigSection<NodeLabelsConfig>
	{
		public NodeLabelsConfig(IConfigSection parent_sect)
			: base(parent_sect)
		{
			this.MetaTemplateType = "meta";
			this.LabelTemplateType = "label";
			this.LabelPath = new BootstrapFsPath(this, "LABEL-NAME");
			this.LocalPath = new BootstrapFsPath(this, "SYNSEM.LOCAL");
			this.LabelFsPath = BootstrapFsPath.Empty;
			this.UppercaseLabel = true;
		}

		public String LabelTemplateType { get; set; }
		public String MetaTemplateType { get; set; }
		public Boolean SimpleTreeDisplay { get; set; }
		public Boolean UppercaseLabel { get; set; }
		public BootstrapFsPath LabelPath { get; set; }
		public BootstrapFsPath PrefixPath { get; set; }
		public BootstrapFsPath SuffixPath { get; set; }
		public BootstrapFsPath RecursivePath { get; set; }
		public BootstrapFsPath LocalPath { get; set; }
		public BootstrapFsPath LabelFsPath { get; set; }
	};
}

